#include <Python.h>
#include <iostream>
#include <ostream>
#include <signal.h>

#include <pulse/pulseaudio.h>
//#include <pulse/glib-mainloop.h>

class PAWrapper{
public:
	PAWrapper(){}
	~PAWrapper(){}
	void Test(){ 
		std::cout<<"Test() callsed"<<std::endl;
	}
	void print(const char*t){
		std::cout<<t<<std::endl;
	}
};


/*
static void dec_outstanding(MainWindow *w) {
    if (n_outstanding <= 0)
        return;

    if (--n_outstanding <= 0)
        w->get_window()->set_cursor();
}

void sink_cb(pa_context *, const pa_sink_info *i, int eol, void *userdata) {
    MainWindow *w = static_cast<MainWindow*>(userdata);

    if (eol) {
        dec_outstanding(w);
        return;
    }

    if (!i) {
        show_error("Sink callback failure");
        return;
    }

    w->updateSink(*i);
}

void source_cb(pa_context *, const pa_source_info *i, int eol, void *userdata) {
    MainWindow *w = static_cast<MainWindow*>(userdata);

    if (eol) {
        dec_outstanding(w);
        return;
    }

    if (!i) {
        show_error("Source callback failure");
        return;
    }

    w->updateSource(*i);
}

void sink_input_cb(pa_context *, const pa_sink_input_info *i, int eol, void *userdata) {
    MainWindow *w = static_cast<MainWindow*>(userdata);

    if (eol) {
        dec_outstanding(w);
        return;
    }

    if (!i) {
        show_error("Sink input callback failure");
        return;
    }

    w->updateSinkInput(*i);
}

void client_cb(pa_context *, const pa_client_info *i, int eol, void *userdata) {
    MainWindow *w = static_cast<MainWindow*>(userdata);

    if (eol) {
        dec_outstanding(w);
        return;
    }

    if (!i) {
        show_error("Client callback failure");
        return;
    }

    w->updateClient(*i);
}

void server_info_cb(pa_context *, const pa_server_info *i, void *userdata) {
    MainWindow *w = static_cast<MainWindow*>(userdata);

    if (!i) {
        show_error("Server info callback failure");
        return;
    }

    w->updateServer(*i);
    dec_outstanding(w);
}

void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata) {
    MainWindow *w = static_cast<MainWindow*>(userdata);

    switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
        case PA_SUBSCRIPTION_EVENT_SINK:
            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
                w->removeSink(index);
            else {
                pa_operation *o;
                if (!(o = pa_context_get_sink_info_by_index(c, index, sink_cb, w))) {
                    show_error("pa_context_get_sink_info_by_index() failed");
                    return;
                }
                pa_operation_unref(o);
            }
            break;

        case PA_SUBSCRIPTION_EVENT_SOURCE:
            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
                w->removeSource(index);
            else {
                pa_operation *o;
                if (!(o = pa_context_get_source_info_by_index(c, index, source_cb, w))) {
                    show_error("pa_context_get_source_info_by_index() failed");
                    return;
                }
                pa_operation_unref(o);
            }
            break;

        case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
                w->removeSinkInput(index);
            else {
                pa_operation *o;
                if (!(o = pa_context_get_sink_input_info(c, index, sink_input_cb, w))) {
                    show_error("pa_context_get_sink_input_info() failed");
                    return;
                }
                pa_operation_unref(o);
            }
            break;

        case PA_SUBSCRIPTION_EVENT_CLIENT:
            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
                w->removeClient(index);
            else {
                pa_operation *o;
                if (!(o = pa_context_get_client_info(c, index, client_cb, w))) {
                    show_error("pa_context_get_client_info() failed");
                    return;
                }
                pa_operation_unref(o);
            }
            break;

        case PA_SUBSCRIPTION_EVENT_SERVER: {
            pa_operation *o;
            if (!(o = pa_context_get_server_info(c, server_info_cb, w))) {
                show_error("pa_context_get_server_info() failed");
                return;
            }
            pa_operation_unref(o);
        }
    }
}
*/

void context_state_callback(pa_context *c, void *userdata) {
    PAWrapper *w = static_cast<PAWrapper*>(userdata);

    //g_assert(c);

    switch (pa_context_get_state(c)) {
        case PA_CONTEXT_UNCONNECTED:
        case PA_CONTEXT_CONNECTING:
        case PA_CONTEXT_AUTHORIZING:
        case PA_CONTEXT_SETTING_NAME:
            break;

        case PA_CONTEXT_READY: {
        	w->print("PA CONTEXT READY");
            /*pa_operation *o;

            pa_context_set_subscribe_callback(c, subscribe_cb, w);

            if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t)
                                           (PA_SUBSCRIPTION_MASK_SINK|
                                            PA_SUBSCRIPTION_MASK_SOURCE|
                                            PA_SUBSCRIPTION_MASK_SINK_INPUT|
                                            PA_SUBSCRIPTION_MASK_CLIENT|
                                            PA_SUBSCRIPTION_MASK_SERVER), NULL, NULL))) {
                show_error("pa_context_subscribe() failed");
                return;
            }
            pa_operation_unref(o);

            if (!(o = pa_context_get_server_info(c, server_info_cb, w))) {
                show_error("pa_context_get_server_info() failed");
                return;
            }
            pa_operation_unref(o);

            if (!(o = pa_context_get_client_info_list(c, client_cb, w))) {
                show_error("pa_context_client_info_list() failed");
                return;
            }
            pa_operation_unref(o);

            if (!(o = pa_context_get_sink_info_list(c, sink_cb, w))) {
                show_error("pa_context_get_sink_info_list() failed");
                return;
            }
            pa_operation_unref(o);

            if (!(o = pa_context_get_source_info_list(c, source_cb, w))) {
                show_error("pa_context_get_source_info_list() failed");
                return;
            }
            pa_operation_unref(o);

            if (!(o = pa_context_get_sink_input_info_list(c, sink_input_cb, w))) {
                show_error("pa_context_get_sink_input_info_list() failed");
                return;
            }
            pa_operation_unref(o);

            n_outstanding = 5;*/

            break;
        }

        case PA_CONTEXT_FAILED:
        	w->print("Connection failed");
            //show_error("Connection failed");
            return;

        case PA_CONTEXT_TERMINATED:
        default:
            //Gtk::Main::quit();
            return;
    }
}


static void PyDelWrapper(void *ptr)
{
    std::cout<<"Called PyDel()\n"; //Good to see once
    PAWrapper * wrap = static_cast<PAWrapper *>(ptr);
    delete wrap;
}

static PyObject* new_wrapper(PyObject*o, PyObject*args)
{
     //dynamically allocate a new object
    PAWrapper *newnum = new PAWrapper();
	
    //wrap the pointer as a "PyCObject" and
    // return that object to the interpreter
    return PyCObject_FromVoidPtr( newnum, PyDelWrapper);
}

static PAWrapper* getObject(PyObject*args){
	PyObject* pyobj;
	int ok = PyArg_ParseTuple(args,"O",&pyobj);
    if(!ok) return NULL;
	// Convert the PyCObject to a void pointer:
	void * temp = PyCObject_AsVoidPtr(pyobj);
	PAWrapper * p = static_cast<PAWrapper *>(temp);
	return p;
}

static PyObject*  pa_print(PyObject* o,PyObject* args){

	PAWrapper* p = getObject(args);
	
	if(p){
		p->Test();
		p=NULL;
	}
	//Py_INCREF(Py_None);
	return Py_None;
}


static PyMethodDef pawrapperMethods[] = { 
  { "new", new_wrapper, METH_VARARGS,  
      "New class." },
  { "test", pa_print, METH_VARARGS,  
      "test me" },
  {NULL, NULL, 0, NULL}
}; 

extern "C" {
	void init_pawrapper(void) { 
	  Py_InitModule("_pawrapper", pawrapperMethods); 
	} 
}
